/*******************************************************************************
 * Copyright (c) 2017, 2025 TeXlipse and others.
 * 
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * https://www.eclipse.org/legal/epl-2.0
 * 
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     The TeXlipse team - initial API and implementation
 *******************************************************************************/

package org.eclipse.texlipse.bibparser;

import org.eclipse.texlipse.bibparser.lexer.Lexer;
import org.eclipse.texlipse.bibparser.lexer.LexerException;
import org.eclipse.texlipse.bibparser.node.EOF;
import org.eclipse.texlipse.bibparser.node.TLBrace;
import org.eclipse.texlipse.bibparser.node.TRBrace;
import org.eclipse.texlipse.bibparser.node.TStringLiteral;
import org.eclipse.texlipse.bibparser.node.TWhitespace;
import org.eclipse.texlipse.bibparser.node.Token;

/**
 * BibTeX lexer. Extends the lexer generated by SableCC from the
 * generation file. Implements handling strings with matched braces.
 * 
 * @author Oskar Ojala
 */
public class BibLexer extends Lexer {

    private int count;
    
    private Token stringStart;
    private StringBuffer text;
    
    /**
     * Constructs a new lexer.
     * 
     * @param in The reader to read the characters from
     */
    public BibLexer(java.io.PushbackReader in) {
        super(in);
    }

    /**
     * We define a filter that recognizes braced strings and removes
     * the preamble and scribe-comments
     */
    protected void filter() throws LexerException {
        
        if (state.equals(State.BRACESTRING)) {
            
            // if we are just entering this state, first token is '{'
            if (stringStart == null) {
                
                stringStart = token;
                text = new StringBuffer("");
                count = 1;
                token = null; // continue to scan the input.
                
            } else {
                if (token instanceof TLBrace)
                    count++;
                else if (token instanceof TRBrace)
                    count--;
                else if (token instanceof EOF) {
                    throw new LexerException("[" + stringStart.getLine() + 
                            "," + stringStart.getPos() + "] Unexpected end of file");
                }
                if (count != 0) {
                    // accumulate the string and continue to scan the input.
                    if (token instanceof TWhitespace)
                        text.append(" ");
                    else
                        text.append(token.getText());
                    token = null;
                } else {
                    TStringLiteral tsl = new TStringLiteral(text.toString(),
                            stringStart.getLine(),
                            stringStart.getPos());
                    // emit the string
                    token = tsl;
                    state = State.ASSIGN; //go back to assign mode
                    stringStart = null;
                }
            }
        } else if (state.equals(State.REMOVE)) {
            if (token instanceof TLBrace) {
                count++;
                if (stringStart == null)
                    stringStart = token;
            } else if (token instanceof TRBrace) {
                count--;
            } else if (token instanceof EOF) {
                throw new LexerException("[" + stringStart.getLine() + 
                        "," + stringStart.getPos() + "] Unexpected end of file");
            }
            token = null;
            if (count == 0 && stringStart != null) {
                state = State.NORMAL;
                stringStart = null;
            }
        }
    }
}
